﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using AventStack.ExtentReports.Utils;
using Ro.AssistFunction.ExtentReport;
using Ro.AssistFunction.OutputManage;
using Ro.AssistFunction.PropertyAction;
using Ro.AssistFunction.SerializerChildNodes;
using Ro.AssistFunction.TypeConversion;
using Ro.Common.RoArgs;
using Ro.Common.RoInterface;
using Ro.Common.RoInterface.UserType;

namespace Ro.Interpreter.RunLogic
{
    //TODO 2017-05-15，更新逻辑关系属性，普通、迭代、循环是3类父层逻辑，宏属于子层逻辑，4类逻辑调用一个单一的运行逻辑核处理对应信息

    /// <summary>
    /// 执行单个testcase节点的方法
    /// Todo 5-4 估计要修改为泛型执行
    /// </summary>
    public class OneTestAction<T>
    {
        /// <summary>
        /// 单个测试用例执行与结果
        /// </summary>
        public bool OneTestResult;


        /// <summary>
        /// 方法具体操作
        /// 执行单个testcase
        /// 需要反馈testcase的执行整体结果
        /// </summary>
        /// <param name="sigInfo">泛型传入值</param>
        /// <returns></returns>
        public OneTestAction(T sigInfo)
        {
            //通过类型进行分类解析

            //普通case
            if (sigInfo.GetType() == typeof(TestcaseInfo))
            {
                TestcaseInfo tempsigInfo = sigInfo as TestcaseInfo;
                OneTestResult = RunTestCase(tempsigInfo);
            }

            //循环
            if (sigInfo.GetType() == typeof(RepeatInfo))
            {
                RepeatInfo tempsigInfo = sigInfo as RepeatInfo;
                OneTestResult = RunRepeat(tempsigInfo);
            }
            //迭代
            if (sigInfo.GetType() == typeof(IterationInfo))
            {
                IterationInfo tempsigInfo = sigInfo as IterationInfo;
                OneTestResult = RunIteration(tempsigInfo);
            }
        }


        private Queue<XmlNode> _macroQueue;

        private string _macroName;


        /// <summary>
        /// 运行TestCase,本方法可能会被RunRepeat、RunIteration调用
        /// <para>本方法是基础方法，无论是Repeat或者Iteration测试逻辑最后的执行归属逻辑均是本方法</para>
        /// </summary>
        /// <param name="sigInfo">TestcaseInfo信息</param>
        private bool RunTestCase(TestcaseInfo sigInfo)
        {
            //初始化
            bool reback;
            try
            {
                //初始化,创建测试
                IRoExtentReport roExtentReport = new RoExtentReport();
                //写入测试执行信息
                roExtentReport.StartExtentReports(sigInfo.TestCaseId, sigInfo.TestCaseAnnotation.Description);

                Queue<XmlNode> logicQueue = new Queue<XmlNode>(); //初始化队列
                //执行步骤
                while (!sigInfo.TestSteps.IsNullOrEmpty())
                {
                    //获取单条步骤节点
                    XmlNode sigTestStepNode = sigInfo.TestSteps.Dequeue();

                    //TODO 假定遭遇到宏，需要再解析一次，并且需要在逻辑层进行解析和执行
                    if (sigTestStepNode.Name == "tcs:MacroReference")
                    {
                        //初始化后将队列返回
                        _macroQueue = new Queue<XmlNode>();
                        RunMacro(sigTestStepNode);
                        foreach (XmlNode tempNode in _macroQueue)
                        {
                            logicQueue.Enqueue(tempNode);
                        }
                    }
                    else
                    {
                        logicQueue.Enqueue(sigTestStepNode);
                    }
                }
                //正式执行
                reback = RunLogicCore(logicQueue);

                //判断单个TestCase是否正确
                roExtentReport.AddTestsResult(reback, sigInfo.TestCaseAnnotation.Description);
            }
            catch (Exception e)
            {
                ExceptionOutPut.SystemExceptionOut("RunTestCase", e);
                reback = false;
            }

            return reback;
        }


        /// <summary>
        /// 运行循环测试
        /// <para>循环测试中的步骤允许包含宏操作，也允许直接包含testcase</para>
        /// </summary>
        /// <param name="sigInfo">RepeatInfo信息</param>
        private bool RunRepeat(RepeatInfo sigInfo)
        {
            //初始化
            bool reback = false;
            try
            {
                //执行循环
                for (int i = 0; i < sigInfo.Counter; i++)
                {
                    //正式开始执行循环内部的步骤
                    while (sigInfo.RepeatSteps.IsNullOrEmpty())
                    {
                        //获取单个节点
                        XmlNode signode = sigInfo.RepeatSteps.Dequeue();
                        if (signode.Name == "tcs:MacroReference")
                        {
                            //初始化,创建测试
                            IRoExtentReport roExtentReport = new RoExtentReport();
                            //写入测试执行信息
                            roExtentReport.StartExtentReports(_macroName, "循环测试_宏");
                            //初始化后将队列返回
                            _macroQueue = new Queue<XmlNode>();
                            RunMacro(signode);
                            //正式执行
                            reback = RunLogicCore(_macroQueue);
                            //判断单个TestCase是否正确
                            roExtentReport.AddTestsResult(reback, "循环测试_宏 名称:"+_macroName);
                        }
                        else
                        {
                            NewSerChildNode newSerChildNode = new NewSerChildNode();
                            TestcaseInfo tempInfo = newSerChildNode.SerTestcaseInfo(signode);
                            reback = RunTestCase(tempInfo);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                ExceptionOutPut.SystemExceptionOut("RunRepeat", e);
                reback = false;
            }

            return reback;
        }


        /// <summary>
        /// 迭代
        /// <para>迭代测试中的步骤允许包含宏操作，也允许直接包含testcase</para>
        /// </summary>
        /// <param name="sigInfo">IterationInfo信息</param>
        private bool RunIteration(IterationInfo sigInfo)
        {
            //初始化
            bool reback = new bool();
            // 反序列化子节点的方法，从下放各个方法提取出，进行共用
            NewSerChildNode newSerChildNode = new NewSerChildNode();

            //循环迭代
            while (sigInfo.IterationList.UseListItems.IsNullOrEmpty())
            {
                string sigitem = sigInfo.IterationList.UseListItems.Dequeue();
                //给定新参数
                Property property = new Property
                {
                    Id = sigInfo.IterationList.Id,
                    Value = sigitem
                };
                //更新参数
                PropertyAction propertyAction = new PropertyAction();
                propertyAction.UpdatePropertyValue(property);

                //开始执行
                XmlNode signode = sigInfo.RepeatSteps.Dequeue();
                if (signode.Name == "tcs:MacroReference")
                {
                    //初始化,创建测试
                    IRoExtentReport roExtentReport = new RoExtentReport();
                    //写入测试执行信息
                    roExtentReport.StartExtentReports(_macroName, "循环测试_宏");
                    //初始化后将队列返回
                    _macroQueue = new Queue<XmlNode>();
                    RunMacro(signode);
                    //正式执行
                    reback = RunLogicCore(_macroQueue);
                    //判断单个TestCase是否正确
                    roExtentReport.AddTestsResult(reback, "循环测试_宏 名称:" + _macroName);
                }
                else
                {
                    TestcaseInfo tempInfo = newSerChildNode.SerTestcaseInfo(signode);
                    reback = RunTestCase(tempInfo);
                }
            }

            return reback;
        }


        /// <summary>
        /// 运行宏
        /// <para>接触到宏后本身不进行运行活动，通过递归的方法组成一个新的队列返回</para>
        /// </summary>
        /// <param name="oneMacros">一个宏的节点</param>
        private void RunMacro(XmlNode oneMacros)
        {
            try
            {
                //初始化转置的类
                XmlAndXElement xmlAndXElement = new XmlAndXElement();

                //添加namespace
                XNamespace tcs = "http://tempuri.org/RoFramework.xsd";
                //转为xelement
                XElement xElement = xmlAndXElement.ToXElement(oneMacros);
                string id = (from idatt in xElement.Attributes() where idatt.Name == tcs + "MacroID" select idatt).Single().Value;

                //从宏列表中查询id值
                ConfMacros macro = (from temp in RoPubArgments.GuiTccInfo.GuiMacros where temp.MacroId == id select temp).Single();
                _macroName = macro.MacroId;
                foreach (XmlNode sigNode in macro.MacroSteps.ChildNodes)
                {
                    //宏内存在宏调用
                    if (sigNode.Name == "tcs:MacroReference")
                    {
                        RunMacro(sigNode);
                    }
                    else
                    {
                        _macroQueue.Enqueue(sigNode);
                    }
                }
            }
            catch (Exception e)
            {
                ExceptionOutPut.SystemExceptionOut("RunMacro", e);
            }
        }


        /// <summary>
        /// 单一运行的逻辑核
        /// <para>用以处理一个被完整处理过的case完整步骤</para>
        /// </summary>
        /// <param name="sigCaseSteps">已经被处理过的单个testcase中的用例</param>
        /// <returns>返回执行结果</returns>
        private bool RunLogicCore(Queue<XmlNode> sigCaseSteps)
        {
            //初始化
            bool reback;
            try
            {
                //初始化结果
                List<bool> allstepsresult = new List<bool>();
                //执行步骤
                while (!sigCaseSteps.IsNullOrEmpty())
                {
                    //获取单条步骤节点
                    XmlNode sigTestStepNode = sigCaseSteps.Dequeue();

                    //执行单步步骤
                    RunStepsQuene sigteststepInfo = new RunStepsQuene(sigTestStepNode);
                    //步骤结果
                    allstepsresult.Add(sigteststepInfo.BackStepResult);
                }
                reback = !allstepsresult.Contains(false);
            }
            catch (Exception e)
            {
                ExceptionOutPut.SystemExceptionOut("RunLogicCore", e);
                reback = false;
            }

            return reback;
        }
    }
}
